#include <stdio.h>
#include <unistd.h>

#include <cctype>
#include <iostream>
#include <memory>
#include <tuple>
#include <vector>

#include "muduo/base/Logging.h"
#include "muduo/net/Channel.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/InetAddress.h"
#include "muduo/net/TcpClient.h"
#include "muduo/net/TcpServer.h"
using namespace muduo;
using namespace muduo::net;
using std::string;
EventLoop loop;
string PORT{"9999"};
string DOMAIN{"localhost"};
std::string message = PORT + DOMAIN;
std::vector<std::unique_ptr<TcpClient>> vt;
string get_port(const string& s_port)
{
    int16_t port = stoi(s_port);
    string res_port;
    while (port) {
        res_port.push_back(char(port));
        port >>= 8;
    }
    return {res_port.rbegin(), res_port.rend()};
}
string sizeToString(const string& port, const string& domain);
string sizeToString(const string& port_domain)
{
    int k = -1;
    while (std::isdigit(port_domain[++k]))
        ;
    return sizeToString(port_domain.substr(0, k), port_domain.substr(k));
}
string sizeToString(const string& port, const string& domain)
{
    string res{"\004\001"};
    res.append(get_port(port));
    // #ifndef DEBUG
    //     std::cout << port << "port\n";
    // #endif
    res.push_back('\000');
    res.push_back('\000');
    res.push_back('\000');
    res.push_back('\001');
    res.push_back('\000');
    res += domain;
    res.push_back('\0');
    return res;
}
int i = 0;
void onConnection(const TcpConnectionPtr& conn)
{
    if (conn->connected()) {
        conn->setTcpNoDelay(true);
        std::cout << "establish " << i << std::endl;
        conn->send(sizeToString(message));
        std::cout << message << "meseeags\n";
    } else {
        printf("onConnection(): connection [%s] is down\n", conn->name().c_str());
        conn->shutdown();
    }
}
void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)
{
    printf("onMessage(): received %zd bytes from connection [%s] at %s\n", buf->readableBytes(),
           conn->name().c_str(), receiveTime.toFormattedString().c_str());
    string s(buf->retrieveAsString(buf->readableBytes()));
    printf("onMessage(): [%s]\n", s.c_str());
    printf("%d\n", s[0] == 0);
    if (s[0] == 0) {
        // conn->forceClose();
        puts("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    } else
        conn->send("hello " + std::to_string(i));
}
int loopCnt = 0;
int N = 8191;
int main(int argc, char** argv)
{
    string t = "localhost";
    setbuf(stdout, NULL);
    if (argc > 2) {
        t = argv[1];
        N = atoi(argv[2]);
    }
    else if(argc > 1) {
        N = atoi(argv[1]);
    }
    printf("%d\n", argc);
    InetAddress serverAddr(t, 9981);
    vt.reserve(N);
    for (i = 0; i < N; ++i) {
        vt.emplace_back(std::make_unique<TcpClient>(&loop, serverAddr, std::to_string(i)));
        
        auto f2 = [t = i, &vt](const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime) {
            printf("onMessage(): received %zd bytes from connection [%s] at %s\n",
                   buf->readableBytes(), conn->name().c_str(),
                   receiveTime.toFormattedString().c_str());
            string s(buf->retrieveAsString(buf->readableBytes()));
            printf("onMessage(): [%s]\n", s.c_str());
            if (s[0] != 0) {
                // printf("%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", t);
                ++loopCnt;
                conn->forceClose();
                vt[t].reset(nullptr);
                if (loopCnt == N) loop.quit();
                
            } else
                conn->send("GET / /HTTP/1.1\r\n\r\n");
        };
        vt.back()->setConnectionCallback(onConnection);
        vt.back()->setMessageCallback(f2);
        vt.back()->enableRetry();
    }
    i = 0;
    for (auto& vti : vt) {
        vti->connect();
        ++i;
    }
    loop.loop();
    return 0;
}
